/*****************************************************************************************
   
   Copyright (c) Microsoft Corporation. All rights reserved.

   Use of this code sample is subject to the terms of the Microsoft
   Permissive License, a copy of which should always be distributed with
   this file.  You can also access a copy of this license agreement at:
   http://www.microsoft.com/resources/sharedsource/licensingbasics/permissivelicense.mspx

 ****************************************************************************************/

using System;

namespace GrooveWebServicesV12Helpers
{
	/// <summary>
	/// A class encapsulating context used for access to Groove Web Services, whether local (Groove running on the same machine as your application)
	/// or remote (Groove running on a remote machine, with Remote Web Services enabled on that machine; usually a server).
	/// 
	/// A Context object is required for access to most functions in this helper library.
	/// Typically you can create a single Context at the beginning of processing, for use during your application's lifetime.
	/// For local Groove access, it is possible for a Context to become invalid, if Groove is shut down and restarted while you retain the Context instance.
	/// </summary>
	public class Context
	{
        private Microsoft.Win32.RegistryKey m_HKCU_GrooveWebServicesRegKey;
        private string m_RequestKey;
        private string m_LocalResponseKey;
		private string m_Host;
		
		private bool m_IsLocal;
		
		private int m_Timeout;

		private const int DEFAULT_TIMEOUT_IN_MILLISECONDS = 90000;  // 90 seconds

        private bool m_Groove12;

		private static int s_TraceEnabled = -1;
		internal static bool TraceEnabled
		{
			get
			{
				if (s_TraceEnabled == -1)
				{
					try 
					{
                        Microsoft.Win32.RegistryKey HKLM_GrooveWebServicesHelpersRegKey = null;

                        #region Look at 32bit registry keys first

                        //  Look for Groove 12 registry key first - if we can't find
                        //  it then use Groove 3.x registry key
						HKLM_GrooveWebServicesHelpersRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(GrooveWebServicesV12Helpers.Shared.GROOVE_12_WEB_SERVICES_HELPERS_REG_KEY);
                        if (HKLM_GrooveWebServicesHelpersRegKey == null)
                            HKLM_GrooveWebServicesHelpersRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(GrooveWebServicesV12Helpers.Shared.GROOVE_WEB_SERVICES_HELPERS_REG_KEY);

                        #endregion

                        if (HKLM_GrooveWebServicesHelpersRegKey == null)
                        {
                            #region Look at Groove 12 Server keys next

                            HKLM_GrooveWebServicesHelpersRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(GrooveWebServicesV12Helpers.Shared.GROOVE_12_SERVER_WEB_SERVICES_HELPERS_REG_KEY);

                            #endregion
                        }

                        if (HKLM_GrooveWebServicesHelpersRegKey == null)
                        {
                            #region Look at 64bit registry keys next

                            //  Look for Groove 12 registry key next - if we can't find
                            //  it then use Groove 3.x registry key
                            HKLM_GrooveWebServicesHelpersRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(GrooveWebServicesV12Helpers.Shared.GROOVE_12_WEB_SERVICES_HELPERS_REG_KEY.Replace(@"Software\", @"Software\Wow6432Node\"));
                            if (HKLM_GrooveWebServicesHelpersRegKey == null)
                                HKLM_GrooveWebServicesHelpersRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(GrooveWebServicesV12Helpers.Shared.GROOVE_WEB_SERVICES_HELPERS_REG_KEY.Replace(@"Software\", @"Software\Wow6432Node\"));

                            #endregion
                        }

                        if (HKLM_GrooveWebServicesHelpersRegKey != null)
						    s_TraceEnabled = (int)HKLM_GrooveWebServicesHelpersRegKey.GetValue("TraceEnabled", 0);
					}
					catch (System.Exception Exception)
					{
						System.Diagnostics.Debug.WriteLine("Context::TraceEnabled Exception - " + Exception.Message);
						s_TraceEnabled = 0;
					}

					if (s_TraceEnabled == 1) // Enable AutoFlush so debug output not lost on crash or exit.
					{
						System.Diagnostics.Debug.AutoFlush = true;
					}
				}

				return (s_TraceEnabled == 1);
			}
		}

        internal bool ReinitNeeded(string i_GrooveRequestHeaderGrooveRequestKey)
        {
            return (i_GrooveRequestHeaderGrooveRequestKey != RequestKey);
        }

        // from: SRX070820600917	PRO/WS/The request was aborted :The request was canceled.System.Net.WebException
        // https://vkbexternal.partners.extranet.microsoft.com/VKBWebService/ViewContent.aspx?scid=SR;US;SRX070820600917 -
        // set these to workaround a bug in the protocol stack
        static Context()
        {
            System.Net.ServicePointManager.MaxServicePointIdleTime = 5000;
            System.Net.ServicePointManager.DefaultConnectionLimit = 24;
        }
        
        /// <summary>
		/// Default constructor.
		/// Creates a Context for access to Groove on the local machine.
		/// </summary>
		public Context() : 
			this("", "", DEFAULT_TIMEOUT_IN_MILLISECONDS)
		{
		}

		/// <summary>
		/// Creates a Context for access to Groove on the local machine.
		/// </summary>
		/// <param name="i_TimeoutInMilliseconds">Timeout, in milliseconds, for the web services calls.  Values greater than 100000 may be required for heavily loaded servers.</param>
		public Context(int i_TimeoutInMilliseconds) :
			this("", "", i_TimeoutInMilliseconds)
		{
		}

		/// <summary>
		/// Creates a Context for access to Groove on a remote machine.
		/// </summary>
		/// <param name="i_RequestKey">The remote request key.</param>
		/// <param name="i_Host">The URL of the Groove instance (http://server:port)</param>
		public Context(string i_RequestKey, string i_Host) :
			this(i_RequestKey, i_Host, DEFAULT_TIMEOUT_IN_MILLISECONDS)
		{
		}

		/// <summary>
		/// Creates a Context from an XmlElement of the format created by SerializeToXml()
		/// </summary>
		/// <param name="i_XmlElement">An XmlElement.</param>
		public Context(System.Xml.XmlElement i_XmlElement) :
			this(i_XmlElement.GetAttribute("RequestKey"), i_XmlElement.GetAttribute("Host"), System.Convert.ToInt32(i_XmlElement.GetAttribute("Timeout")))
		{
		}

		/// <summary>
		/// Creates a Context for access to Groove.
		/// </summary>
		/// <param name="i_RequestKey">The request key for remote access, or null for local access.</param>
		/// <param name="i_Host">The URL of the Groove instance, for remote access</param>
		/// <param name="i_Timeout">Timeout, in milliseconds, for the web services calls.</param>
		public Context(string i_RequestKey, string i_Host, int i_Timeout) :
            this(i_RequestKey, i_Host, i_Timeout, Microsoft.Win32.Registry.CurrentUser)
		{
        }

        public Context(string i_RequestKey, string i_Host, int i_Timeout, Microsoft.Win32.RegistryKey i_RealHKCU)
        {                    
			if (System.String.IsNullOrEmpty(i_RequestKey))
			{
				m_IsLocal = true;

                Microsoft.Win32.RegistryKey HKCU_GrooveRegKey;

                string CurrentVersion = null;

				try 
				{
                    if (i_RealHKCU == null)
                        i_RealHKCU = Microsoft.Win32.Registry.CurrentUser;

                    //  Look for Groove 12 client registry key first
                    HKCU_GrooveRegKey = i_RealHKCU.OpenSubKey(GrooveWebServicesV12Helpers.Shared.GROOVE_12_REG_KEY);

                    //  If we can't find Groove 12 client registry key, 
                    //  look for Groove 12 server registry key
                    if (HKCU_GrooveRegKey == null)
                        HKCU_GrooveRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(GrooveWebServicesV12Helpers.Shared.GROOVE_12_SERVER_REG_KEY);

                    //  If we can't find Groove 12 server registry key,
                    //  look for Groove 3.x registry key
                    if (HKCU_GrooveRegKey == null)
                        HKCU_GrooveRegKey = i_RealHKCU.OpenSubKey(GrooveWebServicesV12Helpers.Shared.GROOVE_REG_KEY);

                    if (HKCU_GrooveRegKey == null)
                        throw new System.Exception("Unable to locate registry key HKCU_GrooveRegKey!");

                    //  Look for Groove 12 client registry key first
                    Microsoft.Win32.RegistryKey HKCU_GrooveWebServicesRegKey = i_RealHKCU.OpenSubKey(GrooveWebServicesV12Helpers.Shared.GROOVE_12_WEB_SERVICES_REG_KEY);

                    //  If we can't find Groove 12 client registry key, 
                    //  look for Groove 12 server registry key
                    if (HKCU_GrooveWebServicesRegKey == null)
                        HKCU_GrooveWebServicesRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(GrooveWebServicesV12Helpers.Shared.GROOVE_12_SERVER_WEB_SERVICES_REG_KEY);

                    //  If we can't find Groove 12 server registry key,
                    //  look for Groove 3.x registry key
                    if (HKCU_GrooveWebServicesRegKey == null)
                        HKCU_GrooveWebServicesRegKey = i_RealHKCU.OpenSubKey(GrooveWebServicesV12Helpers.Shared.GROOVE_WEB_SERVICES_REG_KEY);

                    if (HKCU_GrooveWebServicesRegKey == null)
                        throw new System.Exception("Unable to locate registry key HKCU_GrooveWebServicesRegKey!");

					//  These registry value are required for local SOAP access - they change each time Groove starts up.
                    //m_RequestKey = (string)HKCU_GrooveWebServicesRegKey.GetValue(GrooveWebServicesV12Helpers.Shared.GROOVE_WEB_SERVICES_LOCAL_REQUEST_KEY);
                    //m_LocalResponseKey = (string)HKCU_GrooveWebServicesRegKey.GetValue(GrooveWebServicesV12Helpers.Shared.GROOVE_WEB_SERVICES_LOCAL_RESPONSE_KEY);
                    m_HKCU_GrooveWebServicesRegKey = HKCU_GrooveWebServicesRegKey;

                    //  Look for Groove 12 client registry key first
                    Microsoft.Win32.RegistryKey HKLM_GrooveRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(GrooveWebServicesV12Helpers.Shared.GROOVE_12_REG_KEY);

                    //  If we can't find Groove 12 client registry key, 
                    //  look for Groove 12 server registry key
                    if (HKLM_GrooveRegKey == null)
                        HKLM_GrooveRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(GrooveWebServicesV12Helpers.Shared.GROOVE_12_SERVER_REG_KEY);

                    if (HKLM_GrooveRegKey != null)
                        CurrentVersion = "12.0";
                    else
                    {
                        HKLM_GrooveRegKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(GrooveWebServicesV12Helpers.Shared.GROOVE_REG_KEY);

                        if (HKLM_GrooveRegKey == null)
                            throw new System.Exception("Unable to locate registry key HKLM_GrooveRegKey!");

                        CurrentVersion = (string)HKLM_GrooveRegKey.GetValue(GrooveWebServicesV12Helpers.Shared.GROOVE_CURRENT_VERSION_REG_KEY_NAME);
                    }
				}
				catch (System.Exception Exception)
				{
					System.Diagnostics.Debug.Assert
						(
						false, 
						"Unable to read from Registry: " + Exception.Message, 
						"Fatal Error"
						);

					throw Exception;
				}

                //if (System.String.IsNullOrEmpty(CurrentVersion) || (System.Double.Parse(CurrentVersion) < 3.0))
                //{
                //    throw new System.Exception("You must have Groove 3.0 or a later version installed!");
                //}

                //m_Groove12 = (System.Double.Parse(CurrentVersion) > 11.0);

                System.Version grooveCurrentInstalledVersion = new System.Version(CurrentVersion);
                System.Version grooveMinVersion = new System.Version("3.0");

                if ((CurrentVersion == null) || (grooveCurrentInstalledVersion.CompareTo(grooveMinVersion) < 0))
                {
                    throw new System.Exception("You must have Groove 3.0 or a later version installed!");
                }

                System.Version grooveVersion = new System.Version("11.0");
                m_Groove12 = (grooveCurrentInstalledVersion.CompareTo(grooveVersion) > 0);

				//  Groove registers a port dynamically.  The port defaults to 9080, but
				//  may change in the future.  Local web services clients *must* check
				//  this registry variable to connect to Groove.
				object DesiredGroovePort = HKCU_GrooveRegKey.GetValue(GrooveWebServicesV12Helpers.Shared.GROOVE_HTTP_DESIRED_PORT_REG_KEY_NAME, null);
				if (DesiredGroovePort != null)
					m_Host = "http://localhost:" + DesiredGroovePort.ToString();
				else
				{
					object GroovePort = HKCU_GrooveRegKey.GetValue(GrooveWebServicesV12Helpers.Shared.GROOVE_LOCAL_HTTP_PORT_REG_KEY_NAME, GrooveWebServicesV12Helpers.Shared.GROOVE_DEFAULT_PORT);
					m_Host = "http://localhost:" + GroovePort.ToString();
				}
			}
			else
			{
				m_RequestKey = i_RequestKey;
				m_Host = i_Host;
                m_Groove12 = true;  // damn. let's assume this rather than not (or fix it!) ...tbdtbdtbd ...rgn
			}

			m_Timeout = i_Timeout;
		}

        public static Context NewContext(Context i_OldContext)
        {
            Context newContext = null;
            if (i_OldContext.IsLocal)
            {
                newContext = new Context();
                newContext.m_Groove12 = i_OldContext.Groove12;
            }
            return newContext;
        }

		/// <summary>
		/// Returns true if this Context provides access to Groove on the local machine, false if remote.
		/// </summary>
		public bool IsLocal
		{
			get
			{
				return m_IsLocal;
			}
		}

		/// <summary>
		/// Returns the secret request key.
		/// </summary>
		public string RequestKey
		{
			get
			{
                if (m_IsLocal)
                {
                    m_RequestKey = (string)m_HKCU_GrooveWebServicesRegKey.GetValue(GrooveWebServicesV12Helpers.Shared.GROOVE_WEB_SERVICES_LOCAL_REQUEST_KEY);
                }
				return m_RequestKey;
			}
		}

		/// <summary>
		/// Returns the local response key, used for validating that a response originated from the local Groove executable.
		/// </summary>
		public string LocalResponseKey
		{
			get
			{
                if (m_IsLocal)
                {
                    m_LocalResponseKey = (string)m_HKCU_GrooveWebServicesRegKey.GetValue(GrooveWebServicesV12Helpers.Shared.GROOVE_WEB_SERVICES_LOCAL_RESPONSE_KEY);
                }
				return m_LocalResponseKey;
			}
		}

		/// <summary>
		/// Returns the URL of the Groove instance.
		/// </summary>
		public string Host
		{
			get
			{
				return m_Host;
			}
		}

		/// <summary>
		/// Returns the timeout value in use.
		/// </summary>
		public int Timeout
		{
			get
			{
				return m_Timeout;
			}
		}

        public bool Groove12
        {
            get
            {
                return m_Groove12;
            }

            set
            {
                m_Groove12 = value;
            }
        }

		/// <summary>
		/// Serializes this Context into an XML element.
		/// </summary>
		/// <param name="i_XmlDocument">The owner document.</param>
		/// <returns>A new XmlElement with attributes determined by the Context.</returns>
		public System.Xml.XmlElement SerializeToXml(System.Xml.XmlDocument i_XmlDocument)
		{
			System.Xml.XmlElement ContextXmlElement = i_XmlDocument.CreateElement("Context");

			ContextXmlElement.SetAttribute
				(
				"RequestKey",
				m_RequestKey
				);

			ContextXmlElement.SetAttribute
				(
				"Host",
				m_Host
				);

			ContextXmlElement.SetAttribute
				(
				"Timeout",
				m_Timeout.ToString()
				);

			return ContextXmlElement;
		}
	}
}
